package com.pithypan.service.impl;

import com.pithypan.common.Constants;
import com.pithypan.common.ResponseCodeEnum;
import com.pithypan.common.exceptionHandler.MyException;
import com.pithypan.common.utils.RedisUtils;
import com.pithypan.common.utils.StringTools;
import com.pithypan.dto.SysSettingsDto;
import com.pithypan.entity.EmailCode;
import com.pithypan.entity.UserInfo;
import com.pithypan.mapper.EmailCodeMapper;
import com.pithypan.mapper.UserInfoMapper;
import com.pithypan.service.EmailCodeService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.beans.factory.annotation.Autowired;

import javax.annotation.Resource;
import javax.mail.MessagingException;
import javax.mail.internet.MimeMessage;
import java.util.Date;

/**
 * <p>
 * 邮箱验证码 服务实现类
 * </p>
 *
 * @author author
 * @since 2023-08-24
 */
@Service
@Transactional
public class EmailCodeServiceImpl implements EmailCodeService {

    private static final Logger logger = LoggerFactory.getLogger(EmailCodeServiceImpl.class);

    @Resource
    private UserInfoMapper userInfoMapper;
    @Resource
    private EmailCodeMapper emailCodeMapper;
    @Resource
    private JavaMailSender javaMailSender; //邮箱发送
    @Value("${spring.mail.username}")
    private String sendUserName;           //从配置文件中读取发邮件人账号
    @Resource
    private RedisUtils redisUtils;

    /**
     * 往邮箱发送验证码
     * @param email
     * @param type
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void sendEmailCode(String email, Integer type) {
        UserInfo userInfo = userInfoMapper.selectByEmail(email);
        //type == 0 代表注册  type == 1 代表找回密码
        if (type == 0) {
            if (userInfo != null) { //判断邮箱是否已注册账号
                throw new MyException(ResponseCodeEnum.CODE_404.getCode(), ResponseCodeEnum.CODE_404.getMsg());
            }
        } else {
            if (userInfo == null) { //判断邮箱是否未注册账号
                throw new MyException(ResponseCodeEnum.CODE_414.getCode(), ResponseCodeEnum.CODE_414.getMsg());
            }
        }

        String code = StringTools.getRandomNumber(Constants.LENGTH_5);   //生成5位数的数字验证码
        this.sendMailCode(email, code);                  //发送验证码到邮箱

        emailCodeMapper.disableEmailCode(email);    //将之前发送给该邮箱的所有验证码重置为已使用状态

        EmailCode emailCode = new EmailCode();
        emailCode.setCode(code);
        emailCode.setEmail(email);
        emailCode.setStatus(0);                //false = 0，未使用状态
        emailCode.setCreateTime(new Date());   //邮件发送时间
        emailCodeMapper.insertOne(emailCode);  //添加进数据库
    }


    /**
     * 邮箱验证码发送逻辑
     * @param toEmail
     * @param code
     */
    private void sendMailCode(String toEmail, String code) {

        try {
            MimeMessage message = javaMailSender.createMimeMessage();
            MimeMessageHelper helper = new MimeMessageHelper(message, true);

            //先从redis缓存中获取邮件模板
            SysSettingsDto sysSettingsDto = (SysSettingsDto) redisUtils.get(Constants.REDIS_KEY_SYS_SETTING);
            //缓存中没有邮件设置，则根据默认模版创建一封邮件并存入redis中
            if (sysSettingsDto == null) {
                sysSettingsDto = new SysSettingsDto();
                redisUtils.set(Constants.REDIS_KEY_SYS_SETTING, sysSettingsDto);
            }

            helper.setFrom(sendUserName);      //发件人
            helper.setTo(toEmail);             //收件人
            helper.setSubject(sysSettingsDto.getRegisterEmailTitle());                     //邮件标题
            helper.setText(String.format(sysSettingsDto.getRegisterEmailContent(), code)); //邮件内容
            helper.setSentDate(new Date());    //发送时间

            javaMailSender.send(message);      //发送邮件

        } catch (MessagingException e) {
            logger.error("邮件发送失败", e);
        }
    }


    /**
     *
     * 邮箱验证码校验
     * @param email   邮箱
     * @param code    前端提交的邮箱验证码
     */
    public void checkCode(String email, String code) {
        EmailCode emailCode = emailCodeMapper.selectByEmailAndCode(email, code);
        if (emailCode == null) {
            throw new MyException(ResponseCodeEnum.CODE_603.getCode(), ResponseCodeEnum.CODE_603.getMsg());
        }

        long systemTime = System.currentTimeMillis();
        long infoTime = emailCode.getCreateTime().getTime();
        //判断邮箱验证码是否以被使用 或者 已过期（15分钟）
        if (emailCode.getStatus() == 1 || System.currentTimeMillis() -
                emailCode.getCreateTime().getTime() > 15 * 1000 * 60) {
            throw new MyException(ResponseCodeEnum.CODE_604.getCode(), ResponseCodeEnum.CODE_604.getMsg());
        }
        //至此校验成功，将发送给该邮箱的验证码都重置为以使用状态
        emailCodeMapper.disableEmailCode(email);
    }

}
